/*
Copyright (C) 2008, 2009 Henrik Naess

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/

using System;
using ZoneFiveSoftware.Common.Data;
using ZoneFiveSoftware.Common.Data.GPS;
using ZoneFiveSoftware.Common.Data.Measurement;
using ZoneFiveSoftware.Common.Data.Fitness;
using ZoneFiveSoftware.Common.Visuals;

//This class has parts of the UnitUtil class in GpsRunning plugins and Unit class in Trails
//The code is a little messy right now, can hopefully be cleaned up for ST3 if some API functions are updated.

namespace MatrixPlugin.Utils
{
    public class Formatting
    {
        public const int SecondsPerHour = 3600;

        public static float ParseElevation(string p)
        {
            Length.Units unit = MatrixPlugin.GetApplication().SystemPreferences.ElevationUnits;
            return (float)Length.ParseDistanceMeters(p, ref unit);
        }
        public static string LengthToString(double value, Length.Units units, string fmt)
        {
            return Length.ToString(Length.Convert(
                    value,
                    Length.Units.Meter,
                    units), units, "N" + Length.DefaultDecimalPrecision(units) + fmt);
        }
        public static float GetLength(double value, Length.Units du)
        {
            return (float)Length.Convert(value, Length.Units.Meter, du);
        }

        public static string ElevationString(double value, string fmt)
        {
            Length.Units units = MatrixPlugin.GetApplication().SystemPreferences.ElevationUnits;
            return LengthToString(value, units, fmt);
        }
        public static string DistanceString(double value, string fmt)
        {
            Length.Units units = MatrixPlugin.GetApplication().SystemPreferences.DistanceUnits;
            return LengthToString(value, units, fmt);
        }

#if !ST_2_1
        private static Length GetSpeedLength(IActivity activity, Speed.Units kind)
        {
            Length du;
            if (activity != null)
            {
                du = (kind == Speed.Units.Pace) ? activity.Category.PaceDistance : activity.Category.SpeedDistance;
            }
            else
            {
                du = new Length(1, MatrixPlugin.GetApplication().SystemPreferences.DistanceUnits);
            }
            return du;
        }
#else
        private static Length.Units GetSpeedUnit(ref double speed, IActivity activity, Speed.Units kind)
        {
            Length.Units du;
            if (activity != null)
            {
                du = activity.Category.DistanceUnits;
            }
            else
            {
                du = MatrixPlugin.GetApplication().SystemPreferences.DistanceUnits;
            }
            return du;
        }
#endif
        private static double GetSpeed(double value, ref Length.Units du, IActivity activity, Speed.Units kind)
        {
            //speed is in m/s. convert to display format
            double speed = value;
#if ST_2_1
            du = GetSpeedUnit(ref speed, activity, kind);

            //convert from (x*)m/s to (x*)<unit>/s
            speed = GetLength(speed, du);
#else
            Length speedLength = GetSpeedLength(activity, kind);
            du = speedLength.ValueUnits;
            //scale, custom unit may be other than one
            speed = speed / (float)(speedLength.Value);

            //convert from (x*)m/s to (x*)<unit>/s
            speed = GetLength(speed, du);
#endif
            if (kind == Speed.Units.Speed)
            {
                //speed is <unit>/h
                speed = speed * SecondsPerHour;
            }
            else
            {
                //pace is <time (s)>/<unit>
                speed = 1/speed;
            }
            return (float)speed;
        }

        public static string SpeedString(float meters, TimeSpan time, IActivity activity, string fmt)
        {
            return SpeedString(meters / time.TotalSeconds, activity, fmt);
        }
        public static string SpeedString(double value, IActivity activity, string fmt)
        {
            return SpeedPaceString(value, activity, Speed.Units.Speed, fmt);
        }
        public static string PaceString(float meters, TimeSpan time, IActivity activity, string fmt)
        {
            return PaceString(meters / time.TotalSeconds, activity, fmt);
        }
        public static string PaceString(double value, IActivity activity, string fmt)
        {
            return SpeedPaceString(value, activity, Speed.Units.Pace, fmt);
        }
        public static string SpeedPaceString(double value, IActivity activity, Speed.Units kind, string fmt)
        {
            string result = "";
            string speedUnitLabel = "";
            Length.Units units = Length.Units.Meter;
#if ST_2_1
            //ST3 uses the new Speed.ToString() to get value
            double speed = GetSpeed(value, ref units, activity, kind);
#else
            Length speedLength = GetSpeedLength(activity, kind);
            units = speedLength.ValueUnits;
#endif
            if (fmt.EndsWith("u") || fmt.EndsWith("U"))
            {
                //ST3fix - this can hopefully be changed in final API
                fmt = fmt.Remove(fmt.Length - 1);
#if ST_2_1
                if (kind == Speed.Units.Speed)
                {
                    if (IsMetric(units))
                    {
                        speedUnitLabel = CommonResources.Text.LabelKmPerHour;
                    }
                    else
                    {
                        speedUnitLabel = CommonResources.Text.LabelMilePerHour;
                    }
                }
                else
                {
                    if (IsMetric(units))
                    {
                        speedUnitLabel = CommonResources.Text.LabelMinPerKm;
                    }
                    else
                    {
                        speedUnitLabel = CommonResources.Text.LabelMinPerMile;
                    }
                }
#else
            speedUnitLabel = ZoneFiveSoftware.Common.Data.Measurement.Speed.Label(kind, speedLength);
#endif
                speedUnitLabel = " " + speedUnitLabel;
            }
            if (fmt.Equals(""))
            {
                fmt = "N" + Length.DefaultDecimalPrecision(units);
            }

#if ST_2_1
            result = speed.ToString(fmt);
#else
            result = Speed.ToString(value, new TimeSpan(0, 0, 1), kind, speedLength, fmt);
#endif
            return result + speedUnitLabel;
        }

#if ST_2_1
        public static bool IsMetric(Length.Units unit)
        {
            return (int)unit <= (int)Length.Units.Kilometer;
        }
#endif

        public static string Time(TimeSpan time)
        {
            return string.Format("{0:0}:{1:00}:{2:00}", (int) time.TotalHours, time.Minutes, time.Seconds);
        }
    }
}